#pragma once
#include<iostream>
#include<fstream>
#include <string>
#include<cassert>
#include <vector>
#include <sys/stat.h>
#include"buffer.h"
#include"any.h"
#include"connection.h"
#include <regex>


std::unordered_map<int, std::string> _statu_msg = {
    {100,  "Continue"},
    {101,  "Switching Protocol"},
    {102,  "Processing"},
    {103,  "Early Hints"},
    {200,  "OK"},
    {201,  "Created"},
    {202,  "Accepted"},
    {203,  "Non-Authoritative Information"},
    {204,  "No Content"},
    {205,  "Reset Content"},
    {206,  "Partial Content"},
    {207,  "Multi-Status"},
    {208,  "Already Reported"},
    {226,  "IM Used"},
    {300,  "Multiple Choice"},
    {301,  "Moved Permanently"},
    {302,  "Found"},
    {303,  "See Other"},
    {304,  "Not Modified"},
    {305,  "Use Proxy"},
    {306,  "unused"},
    {307,  "Temporary Redirect"},
    {308,  "Permanent Redirect"},
    {400,  "Bad Request"},
    {401,  "Unauthorized"},
    {402,  "Payment Required"},
    {403,  "Forbidden"},
    {404,  "Not Found"},
    {405,  "Method Not Allowed"},
    {406,  "Not Acceptable"},
    {407,  "Proxy Authentication Required"},
    {408,  "Request Timeout"},
    {409,  "Conflict"},
    {410,  "Gone"},
    {411,  "Length Required"},
    {412,  "Precondition Failed"},
    {413,  "Payload Too Large"},
    {414,  "URI Too Long"},
    {415,  "Unsupported Media Type"},
    {416,  "Range Not Satisfiable"},
    {417,  "Expectation Failed"},
    {418,  "I'm a teapot"},
    {421,  "Misdirected Request"},
    {422,  "Unprocessable Entity"},
    {423,  "Locked"},
    {424,  "Failed Dependency"},
    {425,  "Too Early"},
    {426,  "Upgrade Required"},
    {428,  "Precondition Required"},
    {429,  "Too Many Requests"},
    {431,  "Request Header Fields Too Large"},
    {451,  "Unavailable For Legal Reasons"},
    {501,  "Not Implemented"},
    {502,  "Bad Gateway"},
    {503,  "Service Unavailable"},
    {504,  "Gateway Timeout"},
    {505,  "HTTP Version Not Supported"},
    {506,  "Variant Also Negotiates"},
    {507,  "Insufficient Storage"},
    {508,  "Loop Detected"},
    {510,  "Not Extended"},
    {511,  "Network Authentication Required"}
};
std::unordered_map<std::string, std::string> _mime_msg = {
    {".aac",        "audio/aac"},
    {".abw",        "application/x-abiword"},
    {".arc",        "application/x-freearc"},
    {".avi",        "video/x-msvideo"},
    {".azw",        "application/vnd.amazon.ebook"},
    {".bin",        "application/octet-stream"},
    {".bmp",        "image/bmp"},
    {".bz",         "application/x-bzip"},
    {".bz2",        "application/x-bzip2"},
    {".csh",        "application/x-csh"},
    {".css",        "text/css"},
    {".csv",        "text/csv"},
    {".doc",        "application/msword"},
    {".docx",       "application/vnd.openxmlformats-officedocument.wordprocessingml.document"},
    {".eot",        "application/vnd.ms-fontobject"},
    {".epub",       "application/epub+zip"},
    {".gif",        "image/gif"},
    {".htm",        "text/html"},
    {".html",       "text/html"},
    {".ico",        "image/vnd.microsoft.icon"},
    {".ics",        "text/calendar"},
    {".jar",        "application/java-archive"},
    {".jpeg",       "image/jpeg"},
    {".jpg",        "image/jpeg"},
    {".js",         "text/javascript"},
    {".json",       "application/json"},
    {".jsonld",     "application/ld+json"},
    {".mid",        "audio/midi"},
    {".midi",       "audio/x-midi"},
    {".mjs",        "text/javascript"},
    {".mp3",        "audio/mpeg"},
    {".mpeg",       "video/mpeg"},
    {".mpkg",       "application/vnd.apple.installer+xml"},
    {".odp",        "application/vnd.oasis.opendocument.presentation"},
    {".ods",        "application/vnd.oasis.opendocument.spreadsheet"},
    {".odt",        "application/vnd.oasis.opendocument.text"},
    {".oga",        "audio/ogg"},
    {".ogv",        "video/ogg"},
    {".ogx",        "application/ogg"},
    {".otf",        "font/otf"},
    {".png",        "image/png"},
    {".pdf",        "application/pdf"},
    {".ppt",        "application/vnd.ms-powerpoint"},
    {".pptx",       "application/vnd.openxmlformats-officedocument.presentationml.presentation"},
    {".rar",        "application/x-rar-compressed"},
    {".rtf",        "application/rtf"},
    {".sh",         "application/x-sh"},
    {".svg",        "image/svg+xml"},
    {".swf",        "application/x-shockwave-flash"},
    {".tar",        "application/x-tar"},
    {".tif",        "image/tiff"},
    {".tiff",       "image/tiff"},
    {".ttf",        "font/ttf"},
    {".txt",        "text/plain"},
    {".vsd",        "application/vnd.visio"},
    {".wav",        "audio/wav"},
    {".weba",       "audio/webm"},
    {".webm",       "video/webm"},
    {".webp",       "image/webp"},
    {".woff",       "font/woff"},
    {".woff2",      "font/woff2"},
    {".xhtml",      "application/xhtml+xml"},
    {".xls",        "application/vnd.ms-excel"},
    {".xlsx",       "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"},
    {".xml",        "application/xml"},
    {".xul",        "application/vnd.mozilla.xul+xml"},
    {".zip",        "application/zip"},
    {".3gp",        "video/3gpp"},
    {".3g2",        "video/3gpp2"},
    {".7z",         "application/x-7z-compressed"}
};

class Util {
    public:
        //URL编码，避免URL中资源路径与查询字符串中的特殊字符与HTTP请求中特殊字符产生歧义
        //编码格式：将特殊字符的ascii值，转换为两个16进制字符，前缀%   C++ -> C%2B%2B
        //  不编码的特殊字符： RFC3986文档规定 . - _ ~ 字母，数字属于绝对不编码字符
        //RFC3986文档规定，编码格式 %HH 
        //W3C标准中规定，查询字符串中的空格，需要编码为+， 解码则是+转空格

        //URL编码
        static std::string UrlEncode(const std::string &str,bool is_coding_required=false){
            std::string new_str;
            for(int i=0;i<str.size();i++){
                if(str[i]=='.'||str[i]=='-'||str[i]=='_'||str[i]=='~'||isalnum(str[i])){
                    new_str+=str[i];
                }
                else if(str[i]==' '&&is_coding_required){
                    new_str+='+';
                }
                else{
                    new_str+='%';
                    char hex[4];
                    snprintf(hex,4,"%%%02X",str[i]);
                    new_str+=hex;
                }
            }
            return new_str;
        }
        static int Hexadecimal(char c){
            if(c>='0'&&c<='9'){
                return c-'0';
            }
            else if(c>='A'&&c<='F'){
                return c-'A'+10;
            }
            assert(0);
        }
        //URL解码
        static std::string UrlDecode(const std::string& str,bool is_coding_required=false){
            std::string new_str;
             for(int i=0;i<str.size();i++){
                if(str[i]=='+'&&is_coding_required){
                    new_str+=' ';
                }
                else if(str[i]=='%'){
                    new_str+=(Hexadecimal(str[i+1])<<4);
                    new_str+=Hexadecimal(str[i+2]);
                }
                else{
                    new_str+=str[i];
                }
            }
            return new_str;
        }
        //分割字符串,需要指定分割符
        static void Split(std::string &str,const std::string& sep,std::vector<std::string>& vs){
            int pos=0;
            while(true){
                int next_pos=str.find(sep,pos);
                if(next_pos==std::string::npos){
                    vs.push_back(str.substr(pos));
                    break;
                }
                else{
                    vs.push_back(str.substr(pos,next_pos-pos));
                    pos=next_pos+sep.size();
                }
            }
        }
        //判断一个文件是否是一个目录
        static bool IsDirectory(const std::string &filename) {
            struct stat st;
            int ret = stat(filename.c_str(), &st);
            if (ret < 0) {
                return false;
            }
            return S_ISDIR(st.st_mode);
        }
        //判断一个文件是否是一个普通文件
        static bool IsRegular(const std::string &filename) {
            struct stat st;
            int ret = stat(filename.c_str(), &st);
            if (ret < 0) {
                return false;
            }
            return S_ISREG(st.st_mode);
        }
        //根据文件后缀名获取文件mime
        static std::string ExtMime(const std::string &filename) {
            
            // a.b.txt  先获取文件扩展名
            size_t pos = filename.find_last_of('.');
            if (pos == std::string::npos) {
                return "application/octet-stream";
            }
            //根据扩展名，获取mime
            std::string ext = filename.substr(pos);
            auto it = _mime_msg.find(ext);
            if (it == _mime_msg.end()) {
                return "application/octet-stream";
            }
            return it->second;
        }
        //判断一个路径是否合法
        static bool ValidPath(const std::string& path){
            int dep=0;
            for(int i=0;i<path.size();i++){
                if(path[i]=='/'){
                    dep++;
                }
                else if(path[i]=='.'){
                    if(i+1<path.size()&&path[i+1]=='.'){
                        dep--;
                    }
                }
                if(dep<0){
                    return false;
                }
            }
            return true;
        }
        static void WriteInFile(const std::string& filepath,const std::string& str){
            if(!ValidPath(filepath)){
                assert(0);
            }
            if(!IsRegular(filepath)){
                assert(0);
            }
            std::ofstream ofs(filepath,std::ios::in|std::ios::binary);
            if(!ofs.is_open()){
                assert(0);
            }
            ofs.write(str.c_str(),str.size());
        }
        static void ReadInBuf(const std::string& filepath,Buffer& buf){
            if(!ValidPath(filepath)){
                assert(0);
            }
            if(!IsRegular(filepath)){
                assert(0);
            }
            std::ifstream ifs(filepath,std::ios::out|std::ios::binary);
            if(!ifs.is_open()){
                assert(0);
            }
            char ch;
            std::string str;
            while(ifs.get(ch)){
               str.append(1,ch);
            }
            buf.Write(str);
        }
        //获取状态码对应的消息
        static std::string GetStatus(const std::string& status){
            int a=atoi(status.c_str());
            std::string status_msg;
            if(_statu_msg.find(a)!=_statu_msg.end()){
                status_msg=_statu_msg[a];
            }
            else{
                status_msg="Unknown";
            }
            return status_msg;
        }
};
class Request{
    private:
        std::string _method;//请求方法
        std::string _path;//请求路径
        std::string _version;//HTTP版本
        std::unordered_map<std::string,std::string> _headers;//请求头
        std::string _body;//请求体
    public:
        Request(){}
        void Clear(){
            _method.clear();
            _path.clear();
            _version.clear();
            _headers.clear();
            _body.clear();
        }
        //设置请求方法
        void SetMethod(const std::string& method){  _method=method; }
        //设置请求路径
        void SetPath(const std::string& path){  _path=path; }
        //设置http版本
        void SetVersion(const std::string& version){    _version=version;   }
        //添加请求头
        void AddHeader(const std::string& key,const std::string& value){    _headers[key]=value;    }
        //设置请求体
        void SetBody(const std::string& body){    _body=body;   }
        //获取请求方法
        std::string GetMethod() {    return _method;   }
        //获取请求路径
        std::string GetPath() {    return _path;   }
        //获取http版本
        std::string GetVersion(){    return _version;   }
        //获取请求头
        std::unordered_map<std::string,std::string> GetHeaders(){    return _headers;   }
        //获取请求头，如果不存在则返回空字符串
        std::string GetHeader(const std::string& key)  {
            if(_headers.find(key)==_headers.end()){
                return "";
            }
            return _headers[key];  
        }
        //获取请求体
        std::string GetBody(){    return _body;   }
        //判断是否为长链接
        bool IsKeepAlive(){
            std::string connection=GetHeader("Connection");
            if(connection=="keep-alive"||connection=="Keep-Alive"){
                return true;
            }
            return false;
        }
};
class Response{
    private:
        bool _redirect_flag;//是否重定向
        int _status;//状态码
        std::string _version;//HTTP版本
        std::string _body;//响应体
        std::unordered_map<std::string,std::string> _headers;//响应头
    public:
        Response():_status(200),_version("HTTP/1.1"){}
        void Clear(){
            _redirect_flag=false;
            _status=200;
            _version.clear();
            _body.clear();
            _headers.clear();
        }
        //设置状态码
        void SetStatus(int status){    _status=status;   }
        //设置http版本
        void SetVersion(const std::string& version){    _version=version;   }
        //设置响应体
        void SetBody(const std::string& body){    _body=body;   }
        //添加响应头
        void AddHeader(const std::string& key,const std::string& value){    _headers[key]=value;    }
        //获取状态码
        int GetStatus()const {    return _status;   }
        //获取http版本
        const std::string GetVersion()const {    return _version;   }
        //获取响应体
        std::string GetBody()const {    return _body;   }
        //获取所有响应头
        std::unordered_map<std::string,std::string> GetHeaders()const {    return _headers;   }
        //获取响应头，如果不存在则返回空字符串
        std::string GetHeader(const std::string& key)  {
            if(_headers.find(key)==_headers.end()){
                return "";
            }
            return _headers[key];   
        }
        //设置重定向标志
        void SetRedirectFlag(bool flag){    _redirect_flag=flag;   }
        //是否重定向
        bool IsRedirectFlag(){    return _redirect_flag;   }
};
enum Status{
            RECV_REQUEST_LINE,//读取请求行
            RECV_HEADERS,//读取请求头
            RECV_BODY,//读取请求体
            FINISHED,//结束
            RECV_HTTP_ERROR//接收HTTP错误
        };
class HttpContext{
    private:
        Status _status;//接收情况
        int _resp_statu;//响应状态码
        Request _request;//请求
    private:
        //处理请求行
        bool ProcessRequestLine(std::string& line){
            if(_status!=RECV_REQUEST_LINE){
                return false;
            }
            std::smatch matches;
            std::regex e("(GET|HEAD|POST|PUT|DELETE) ([^?]*)(?:\\?(.*))? (HTTP/1\\.[01])(?:\n|\r\n)?", std::regex::icase);
            bool ret = std::regex_match(line, matches, e);
            if (ret == false) {
                _status = RECV_HTTP_ERROR;
                _resp_statu = 400;//BAD REQUEST
                return false;
            }
            _request.SetMethod(matches[1]);
            //在url中可能存在需要解析的字符
            _request.SetPath(Util::UrlDecode(matches[2],0));
            if (matches[3].matched) {
                std::string query_string = matches[3];
                std::vector<std::string> query_vs;
                Util::Split(query_string, "&", query_vs);
                for (auto& query : query_vs) {
                    std::vector<std::string> kv;
                    Util::Split(query, "=", kv);
                    if (kv.size() == 2) {
                        _request.AddHeader(kv[0], kv[1]);
                    }
                }
            }
            _request.SetVersion(matches[4]);
            _status=RECV_HEADERS;
            return true;
        }
        //处理请求头,一次处理一行
        bool ProcessHeaders(std::string& line){
            if(_status!=RECV_HEADERS){
                return false;
            }
            if(line.back()=='\n') line.pop_back();
            if(line.back()=='\r') line.pop_back();
            if(line.empty()){
                _status=RECV_BODY;
                return true;
            }
            int pos=line.find(":");
            if(pos==std::string::npos){
                perror("invalid header line");
                _status=RECV_HTTP_ERROR;
                _resp_statu=400;
                return false;
            }
            std::string key=line.substr(0,pos);
            std::string value=line.substr(pos+1);
            _request.AddHeader(key,value);
            return true;
        }
        std::string RecvBody(Buffer* buf){
            if(_status!=RECV_BODY){
                _status=RECV_HTTP_ERROR;
                return "";
            }
            //获取请求体长度,检查是否有完整的请求体
            std::string body_len=_request.GetHeader("Content-Length");
            if(body_len.empty()){
                _status=RECV_HTTP_ERROR;
                return "";
            }
            int len=atoi(body_len.c_str());
            if(len<0){
                _status=RECV_HTTP_ERROR;
                return "";
            }
            std::string body= buf->ReadAndPop(len);
            return body;
        }
        //处理请求体
        bool ProcessBody(std::string& line){
            if(_status!=RECV_BODY){
                return false;
            }
            //获取请求体长度,检查是否有完整的请求体
            _request.SetBody(line);
            _status=FINISHED;
            return true;
        }
        //设置响应状态码
        void SetRespStatus(int status){
            _resp_statu=status;
        }
        //获取一行
        std::string GetLine(Buffer& buf){
            std::string line;
            line=buf.GetLineAndPop();
            return line;
        }
    public:
        HttpContext():_resp_statu(200),_status(RECV_REQUEST_LINE){
            _request.Clear();
        }
        void Clear(){
            _status=RECV_REQUEST_LINE;
            _request.Clear();
            _resp_statu=200;
        }
        //获取响应状态码
        int GetRespStatus(){    return _resp_statu;   }
        //获取请求
        Request& GetRequest(){    return _request;   }
        Status GetStatus(){    return _status;   }
        bool IsKeepAlive(){
            return _request.IsKeepAlive();
        }
        //读取请求
        void ReadParseRequest(Buffer* buf){
            //为什么不用else if,尝试处理完整的请求
            if(_status==RECV_REQUEST_LINE){
                std::string line=buf->GetLineAndPop();
                ProcessRequestLine(line);
            }
            if(_status==RECV_HEADERS){
                while(_status==RECV_HEADERS){
                    std::string line=buf->GetLineAndPop();
                    LOG(ly::LogLevel::DEBUG)<<line;
                    sleep(2);
                    ProcessHeaders(line);
                }
            }
            if(_status==RECV_BODY){
                std::string body=RecvBody(buf);
                ProcessBody(body);
            }
        }
};

class HttpServer{
    private:
        using RequestProcessingMethod=std::function<void (Request& ,Response&)>;
        RequestProcessingMethod _get_processing_method;
        RequestProcessingMethod _post_processing_method;
        RequestProcessingMethod _put_processing_method;
        RequestProcessingMethod _delete_processing_method;
        //RequestHandlingMethod _head_handling_method;
        std::string _root_path;//静态资源根目录
        TcpServer _server;
        void ErrorProcessing(Response& rep,int err_code){
            rep.SetStatus(err_code);
            std::string s = "<!DOCTYPE html>"
                        "<html lang=\"zh-CN\">"
                        "<head>"
                        "<meta charset=\"UTF-8\">"
                        "<meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\">"
                        "<title>404 - 页面未找到</title>"
                        "<style>"
                        "body { margin: 0; padding: 20px; font-family: sans-serif; background: #f9fafb; display: flex; flex-direction: column; align-items: center; justify-content: center; min-height: 100vh; }"
                        "h1 { font-size: 64px; margin: 0 0 16px; color: #1f2937; }"
                        "h2 { font-size: 20px; margin: 0 0 24px; color: #4b5563; }"
                        "a { background: #2563eb; color: white; padding: 10px 20px; border-radius: 6px; text-decoration: none; }"
                        "a:hover { background: #1d4ed8; }"
                        "</style>"
                        "</head>"
                        "<body>"
                        "<h1>404</h1>"
                        "<h2>页面未找到</h2>"
                        "<a href=\"/\">返回首页</a>"
                        "</body>"
                        "</html>";
            rep.SetBody(s);
            rep.AddHeader("Content-Type","text/html");
            rep.AddHeader("Content-Length",std::to_string(s.size()));
        }
        //将应答组装成字符串
        void AssembleResponse(Response& rep,std::string& rep_str){
            //组装响应行
            rep_str.append(rep.GetVersion());
            rep_str.append(" ");
            rep_str.append(std::to_string(rep.GetStatus())+"\r\n");
            //添加响应头
            for(auto& header:rep.GetHeaders()){
                rep_str.append(header.first);
                rep_str.append(": ");
                rep_str.append(header.second);
                rep_str.append("\r\n");
            }
            rep_str.append("\r\n");
            //添加响应体
            rep_str.append(rep.GetBody());
        }
        bool IsItLegal(Request& req){
            if(_root_path.empty()){
                return false;
            }
            std::string path=req.GetPath();
            if(Util::ValidPath(path)==false){
                return false;
            }
            if(path=="/"){
                path=_root_path+"/index.html";
            }
            if(Util::IsRegular(path)==false){
                return false;
            }
            return true;
        }
        void RespondStaticResources(Request& req,Response& rep){
            if(IsItLegal(req)==false){
                ErrorProcessing(rep,403);
                return;
            }
            std::string path=req.GetPath();
            if(path=="/"){
                path=_root_path+"/index.html";
            }
            std::ifstream ifs(path,std::ios::in|std::ios::binary);
            if(!ifs.is_open()){
                ErrorProcessing(rep,404);
                return;
            }
            std::string body;
            char ch;
            while(ifs.get(ch)){
                body.append(1,ch);
            }
            rep.SetBody(body);
            rep.AddHeader("Content-Type",Util::ExtMime(path));
            rep.AddHeader("Content-Length",std::to_string(body.size()));
        }
        void RequestProcessing(Request& req,Response& rep){
            if(req.GetMethod()=="GET"){
                assert(_get_processing_method);
                _get_processing_method(req,rep);
            }
            else if(req.GetMethod()=="POST"){
                assert(_post_processing_method);
                _post_processing_method(req,rep);
            }
            else if(req.GetMethod()=="PUT"){
                assert(_put_processing_method);
                _put_processing_method(req,rep);
            }
            else if(req.GetMethod()=="DELETE"){
                assert(_delete_processing_method);
                _delete_processing_method(req,rep);    
            }
            else{
                ErrorProcessing(rep,405);
            }
        }
        void MessageProcessing( Connection* conn,Buffer* buf){
            while(buf->GetSize()>0){
                const Any& any=conn->GetAny();
                HttpContext* hc=any.GetVal<HttpContext>();
                if(hc==nullptr){
                    assert(0);exit(1);
                }
                Request& req=hc->GetRequest();
                hc->ReadParseRequest(buf);
                if(hc->GetStatus()==RECV_HTTP_ERROR){
                    Response rep;
                    ErrorProcessing(rep,400);
                    std::string rep_str;
                    AssembleResponse(rep,rep_str);
                    conn->Send(rep_str,rep_str.size());
                    hc->Clear();
                    buf->Clear();
                    conn->Close();
                    return;
                }
                if(hc->GetStatus()!=FINISHED){
                    break;
                }
                std::string rep_str;
                Response rep;
                RequestProcessing(req,rep);
                AssembleResponse(rep,rep_str);
                conn->Send(rep_str,0);
                LOG(ly::LogLevel::DEBUG)<<rep_str;
                if(!hc->IsKeepAlive()) {
                    conn->Close();
                    return;
                }
            }
        }
        void ConnectionCallback(Connection* conn){
            HttpContext hc;
            conn->SetContext(Any(hc));
        }
    public:
        HttpServer(int port,int thread_num=1,int timeout=30):_server(port,thread_num,timeout){
            _server.SetMessageCallback(std::bind(&HttpServer::MessageProcessing,this,std::placeholders::_1,std::placeholders::_2));
            _server.SetConnectedCallback(std::bind(&HttpServer::ConnectionCallback,this,std::placeholders::_1));
            _server.EnableInactiveRelease(15);
        }
        // RequestProcessingMethod _get_processing_method;
        // RequestProcessingMethod _post_processing_method;
        // RequestProcessingMethod _put_processing_method;
        // RequestProcessingMethod _delete_processing_method;
        void SetRootPath(const std::string& root_path){
            _root_path=root_path;
        }
        void SetGet(RequestProcessingMethod method){
            _get_processing_method=method;
        }
        void SetPost(RequestProcessingMethod method){
            _post_processing_method=method;
        }
        void SetPut(RequestProcessingMethod method){
            _put_processing_method=method;
        }
        void SetDelete(RequestProcessingMethod method){
            _delete_processing_method=method;
        }
        void SetThreadNum(int num){
            _server.SetThreadcnt(num);
        }
        void Start(){
            _server.Start();
        }
};